#pragma once

#include <iostream>
#include <string>
#include <unordered_map>
#include <cstdlib>
#include <sys/epoll.h>
#include <unistd.h>

#define SIZE 128
#define NUM 64

class Event;
class Reactor;

typedef int (*callback_t)(Event *ev); //函数指针

//先描述被管理的fd结构
class Event
{
public:
    int sock; //对应文件描述符

    std::string inbuffer;  //对应的sock,对应的输入缓冲区
    std::string outbuffer; //对应的sock,对应的输出缓冲区

    // sock设置回调
    callback_t recver;
    callback_t sender;
    callback_t errorer;

    // Event回指Reactor的指针
    Reactor *R;

public:
    Event()
    {
        sock = -1;
        recver = nullptr;
        sender = nullptr;
        errorer = nullptr;
        R = nullptr;
    }
    void RegisterCallback(callback_t _recver, callback_t _sender, callback_t _errorer)
    {
        recver = _recver;
        sender = _sender;
        errorer = _errorer;
    }
    ~Event()
    {
    }
};

//再组织
// Reactor : Event = 1 : n
class Reactor
{
private:
    int epfd;
    std::unordered_map<int, Event *> events; //文件描述符和对应的Event结构
public:
    Reactor() : epfd(-1)
    {
    }
    void InitReactor()
    {
        epfd = epoll_create(SIZE);
        if (epfd < 0)
        {
            std::cerr << "epoll_create error" << std::endl;
            exit(2);
        }
        std::cout << "InitReactor success" << std::endl;
    }
    bool InsertEvent(Event *evp, uint32_t evs)
    {
        // 1、将sock插入epoll中
        struct epoll_event ev;
        ev.events = evs; // evs就是要关心的事件
        ev.data.fd = evp->sock;
        //成功返回0，失败返回-1
        if (epoll_ctl(epfd, EPOLL_CTL_ADD, evp->sock, &ev) < 0)
        {
            std::cerr << "epoll_ctl add event failed" << std::endl;
            return false;
        }
        // 2、将ev自身插入unorder_map中
        events.insert({evp->sock, evp});
    }
    void DeleteEvent(Event *evp)
    {
        int sock = evp->sock;
        auto iter = events.find(sock);
        if (iter != events.end())
        {
            // 1、将sock从epoll中删除
            epoll_ctl(epfd, EPOLL_CTL_DEL, sock, nullptr);

            // 2、在map中删除sock
            events.erase(iter);

            // 3、close
            close(sock);

            // 4、删除event节点
            delete evp;
        }
    }

    //读写开关
    bool EnableRW(int sock, bool enbread, bool enbwrite)
    {
        struct epoll_event ev;
        ev.events = EPOLLET | (enbread ? EPOLLIN : 0) | (enbwrite ? EPOLLOUT : 0);
        ev.data.fd = sock;

        if (epoll_ctl(epfd, EPOLL_CTL_MOD, sock, &ev) < 0)
        {
            std::cerr << "epoll_ctl mod event failed" << std::endl;
            return false;
        }
        return true;
    }

    bool IsSockOk(int sock)
    {
        auto iter = events.find(sock);
        return iter != events.end();
    }

    //就绪事件的派发器逻辑
    void Dispatcher(int timeout)
    {
        struct epoll_event revs[NUM];
        int n = epoll_wait(epfd, revs, NUM, timeout);
        // n等于0和小于0循环都不会执行
        // 所以执行循环时说明等待成功
        for (int i = 0; i < n; i++)
        {
            int sock = revs[i].data.fd;
            uint32_t revents = revs[i].events;

            //差错处理，将所有的错误问题全部转化成为让IO函数去解决
            //如果revents上的事件出错，就归类于读事件或写事件
            if (revents & EPOLLERR)
                revents |= (EPOLLIN | EPOLLOUT);
            //出现EPOLLHUP代表对端断开
            if (revents & EPOLLHUP)
                revents |= (EPOLLIN | EPOLLOUT);

            //读事件就绪
            if (revents & EPOLLIN)
            {
                //直接调用回调方法执行对应读取
                if (IsSockOk(sock) && events[sock]->recver)
                    events[sock]->recver(events[sock]);
            }

            //写事件就绪
            if (revents & EPOLLOUT)
            {
                if (IsSockOk(sock) && events[sock]->sender)
                    events[sock]->sender(events[sock]);
            }
        }
    }

    ~Reactor() {}
};